import { ArrayUtil as tsxArrayUtil } from "./ArrayUtil";
import { DateUtil as tsxDateUtil } from "./DateUtil";
import { MathUtil as tsxMatchUtil } from "./MathUtil";
import { ObjectUtil as tsxObjectUtil } from "./ObjectUtil";
import { RandomUtil as tsxRandomUtil } from "./RandomUtil";
import { StringUtil as tsxStringUtil } from "./StringUtil";


// import {
//     getVarType, isNull, isEmpty,
//     isNumber, isObject, isArray, isFunction, isString, isBoolean,
//     isDate, isMap, isSet, isRegexp,
// } from "./TsUtil";
// import { inRange, deepCopy, equal, approximatelyEqual, } from "./TsUtil";
// import { forEach, forIn, find, } from "./TsUtil";
// import { groupBy, Coop, wait, sleep, debounce, } from "./TsUtil";

// let attachFunctionName = [
//     "getVarType", "isNull", "isEmpty", "isNumber",
//     "isObject", "isArray", "isFunction", "isString", "isBoolean",
//     "isDate", "isMap", "isSet", "isRegexp",
//     "inRange", "deepCopy", "equal", "approximatelyEqual",
//     "forEach", "forIn", "find",
//     "groupBy", "Coop", "wait", "sleep", "debounce",
// ]

// let attachFunction = [
//     getVarType, isNull, isEmpty, isNumber,
//     isObject, isArray, isFunction, isString, isBoolean,
//     isDate, isMap, isSet, isRegexp,
//     inRange, deepCopy, equal, approximatelyEqual,
//     forEach, forIn, find,
//     groupBy, Coop, wait, sleep, debounce,
// ]

// let gThis = globalThis || window;

// if (gThis) {
//     attachFunctionName.forEach(function (name, index) {
//         if (!Object.prototype.hasOwnProperty(name))
//             gThis[name] = attachFunction[index];
//     });
// }

import * as tsUtil from "./TsUtil";
let gThis = (globalThis || window) as any;
if (gThis) {
    let ut = tsUtil as any;
    for (const key in ut) {
        if (!Object.prototype.hasOwnProperty.call(gThis, key)) {
            gThis[key] = ut[key]
        }
    }
}

namespace __tsx__ {
    export const arrayx = tsxArrayUtil;
    export type arrayx = tsxArrayUtil;

    export const datex = tsxDateUtil;
    export type datex = tsxDateUtil;

    export const matchx = tsxMatchUtil;
    export type matchx = tsxMatchUtil;

    export const objectx = tsxObjectUtil;
    export type objectx = tsxObjectUtil;

    export const randomx = tsxRandomUtil;
    export type randomx = tsxRandomUtil;

    export const stringx = tsxStringUtil;
    export type stringx = tsxStringUtil;
}

(gThis as any)['tsx'] = __tsx__;
if (gThis) {
    let tsx = __tsx__ as any;
    for (const key in tsx) {
        if (!Object.prototype.hasOwnProperty.call(gThis, key)) {
            gThis[key] = tsx[key]
        }
    }
}

declare global {
    namespace globalThis {
        namespace tsx {

            const arrayx: typeof tsxArrayUtil;
            type arrayx = tsxArrayUtil;

            const datex: typeof tsxDateUtil;
            type datex = tsxDateUtil;

            const matchx: typeof tsxMatchUtil;
            type matchx = tsxMatchUtil;

            const objectx: typeof tsxObjectUtil;
            type objectx = tsxObjectUtil;

            const randomx: typeof tsxRandomUtil;
            type randomx = tsxRandomUtil;

            const stringx: typeof tsxStringUtil;
            type stringx = tsxStringUtil;

        }

        const arrayx: typeof tsxArrayUtil;
        type arrayx = tsxArrayUtil;

        const datex: typeof tsxDateUtil;
        type datex = tsxDateUtil;

        const matchx: typeof tsxMatchUtil;
        type matchx = tsxMatchUtil;

        const objectx: typeof tsxObjectUtil;
        type objectx = tsxObjectUtil;

        const randomx: typeof tsxRandomUtil;
        type randomx = tsxRandomUtil;

        const stringx: typeof tsxStringUtil;
        type stringx = tsxStringUtil;

        function getVarType(value: any): string;
        function isNull(value: any): boolean;
        function isEmpty(value: any): boolean
        function isNumber(value: any): boolean

        function isObject(value: any): boolean
        function isArray(value: any): boolean
        function isFunction(value: any): boolean
        function isString(value: any): boolean
        function isBoolean(value: any): boolean

        function isDate(value: any): boolean
        function isMap(value: any): boolean
        function isSet(value: any): boolean
        function isRegexp(value: any): boolean

        function inRange(min: number, max: number, value: number, includeEdge?: boolean): boolean
        function deepClone<T>(target: T): T

        function plainToInstance<T, W>(cls: new () => T, json: object & W): T & W;
        function plainToInstance<T>(cls: new () => T, json: string): T;

        function equal<T, U>(value: T, other: U): boolean;
        function approximatelyEqual(a: number, b: number, epsilon?: number): boolean

        function forEach<T>(length: number, iterator: (index?: number) => boolean | void, step?: number): void;
        function forEach<T>(array: Array<T>, iterator: (value?: T, index?: number, array?: Array<T>) => boolean | void, step?: number, startIndex?: number): void;
        function forEach<T>(array: Array<T>, iterator: (value: T, index: number, array: Array<T>) => boolean | void, step?: number, startIndex?: number): void;

        function forIn<T, U>(object: T, iterator: (value?: U, key?: string, object?: T) => boolean | void): void

        function find<T, U, V>(array: Array<T>, predicate: [U, V], defaultValue?: T | null, fromIndex?: number): T;
        function find<T>(array: Array<T>, predicate: (item: T) => any, defaultValue?: T | null, fromIndex?: number): T;
        function find<T>(array: Array<T>, predicate: Object, defaultValue?: T | null, fromIndex?: number): T;
        function find<T>(array: Array<T>, predicate: number, defaultValue?: T | null, fromIndex?: number): { index: number, value: number };
        function find<T>(array: Array<T>, predicate: string, defaultValue?: T | null, fromIndex?: number): T;

        function groupBy<T, U>(array: Array<T>, generateKey: string): Array<U>[];
        function groupBy<T, U>(array: Array<T>, generateKey: ((item: T) => string)): Array<U>[];

        function Coop<T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: T | PromiseLike<T>) => void) => void, onFullfiled?: ((value: T) => T | PromiseLike<T>) | undefined | null, onRejected?: ((reason: T) => T | PromiseLike<T>) | undefined | null): Promise<T>
        function wait(msec: number): Promise<void>
        function sleep(msec: number): Promise<void>
        function debounce(fun: Function, duration?: number): (...args: any) => number

    }
}
